<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Element Plus 组件动态插入系统</title>
  <link rel="stylesheet" href="https://unpkg.com/element-plus/dist/index.css">
  <script src="https://unpkg.com/vue@3"></script>
  <script src="https://unpkg.com/element-plus"></script>
  <script src="https://unpkg.com/@element-plus/icons-vue"></script>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
      font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
    }
    
    body {
      background: linear-gradient(135deg, #1a2980, #26d0ce);
      min-height: 100vh;
      display: flex;
      justify-content: center;
      align-items: center;
      padding: 20px;
    }
    
    .dashboard {
      display: grid;
      grid-template-columns: 360px 1fr;
      gap: 30px;
      width: 100%;
      max-width: 1200px;
      min-height: 85vh;
      background: rgba(255, 255, 255, 0.95);
      border-radius: 18px;
      box-shadow: 0 15px 35px rgba(0, 0, 0, 0.25);
      overflow: hidden;
      position: relative;
      z-index: 10;
    }
    
    header {
      background: linear-gradient(90deg, #409eff, #337ecc);
      padding: 25px 30px;
      color: white;
      grid-column: 1 / -1;
      border-radius: 18px 18px 0 0;
    }
    
    .logo-area {
      display: flex;
      align-items: center;
      gap: 15px;
    }
    
    .main-title {
      font-size: 1.8rem;
      font-weight: 700;
      letter-spacing: 0.5px;
    }
    
    .subtitle {
      font-size: 1rem;
      opacity: 0.9;
      margin-top: 5px;
    }
    
    .sidebar {
      padding: 25px;
      background: #f8f9ff;
      border-right: 1px solid #ebedf0;
    }
    
    .component-list {
      display: grid;
      grid-template-columns: repeat(2, 1fr);
      gap: 15px;
      margin-top: 20px;
    }
    
    .component-card {
      background: white;
      border-radius: 10px;
      padding: 15px;
      box-shadow: 0 3px 10px rgba(0, 0, 0, 0.03);
      transition: all 0.3s ease;
      border: 1px solid #e4e7ed;
      cursor: pointer;
    }
    
    .component-card:hover {
      transform: translateY(-3px);
      box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
      border-color: #409eff;
    }
    
    .component-card h3 {
      font-size: 1rem;
      color: #303133;
      margin-bottom: 10px;
      display: flex;
      align-items: center;
      gap: 8px;
    }
    
    .component-card .desc {
      font-size: 0.85rem;
      color: #606266;
    }
    
    .config-panel {
      padding: 20px;
      background: #fff;
      border-radius: 12px;
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.03);
      margin-top: 25px;
    }
    
    .config-header {
      display: flex;
      align-items: center;
      gap: 10px;
      padding-bottom: 15px;
      border-bottom: 1px solid #ebeef5;
      margin-bottom: 15px;
    }
    
    .panel-content {
      display: grid;
      gap: 15px;
    }
    
    .panel-row {
      display: grid;
      grid-template-columns: 100px 1fr;
      align-items: center;
    }
    
    .panel-label {
      font-weight: 500;
      color: #606266;
      font-size: 0.95rem;
    }
    
    .editor-area {
      padding: 25px;
      display: flex;
      flex-direction: column;
      position: relative;
    }
    
    .editor-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding-bottom: 20px;
      margin-bottom: 20px;
      border-bottom: 1px solid #ebeef5;
    }
    
    .toolbar {
      display: flex;
      gap: 10px;
    }
    
    .viewport-container {
      position: relative;
      background: white;
      border-radius: 12px;
      flex-grow: 1;
      overflow: auto;
      box-shadow: 0 0 15px rgba(0, 0, 0, 0.05);
      padding: 25px;
      border: 1px solid #e4e7ed;
    }
    
    .parent-container {
      min-height: 300px;
      min-width: 300px;
      position: relative;
      border: 2px dashed #409eff;
      border-radius: 10px;
      padding: 20px;
      background: rgba(238, 242, 255, 0.3);
    }
    
    .child-wrapper {
      position: relative;
      display: inline-block;
      margin: 15px;
      transition: all 0.3s ease;
    }
    
    .size-label {
      position: absolute;
      top: -28px;
      left: 0;
      background: rgba(64, 158, 255, 0.9);
      color: white;
      padding: 4px 10px;
      border-radius: 6px;
      font-size: 0.8rem;
      font-weight: 500;
      z-index: 20;
      box-shadow: 0 2px 8px rgba(64, 158, 255, 0.3);
    }
    
    .close-btn {
      position: absolute;
      top: -15px;
      right: -15px;
      width: 28px;
      height: 28px;
      border-radius: 50%;
      background: #ff4d4f;
      color: white;
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      z-index: 30;
      box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
      font-size: 0.9rem;
      opacity: 0;
      transition: opacity 0.3s;
    }
    
    .child-wrapper:hover .close-btn {
      opacity: 1;
    }
    
    .info-panel {
      position: absolute;
      bottom: 20px;
      right: 20px;
      background: rgba(255, 255, 255, 0.9);
      border-radius: 12px;
      padding: 15px;
      box-shadow: 0 3px 12px rgba(0, 0, 0, 0.1);
      border: 1px solid #dcdfe6;
    }
    
    .info-title {
      font-weight: 600;
      margin-bottom: 10px;
      color: #409eff;
      display: flex;
      align-items: center;
      gap: 8px;
    }
    
    .info-grid {
      display: grid;
      grid-template-columns: auto auto;
      gap: 10px 20px;
    }
    
    .info-label {
      font-weight: 500;
      color: #606266;
      font-size: 0.9rem;
    }
    
    .info-value {
      font-weight: 600;
      color: #303133;
    }
    
    @media (max-width: 800px) {
      .dashboard {
        grid-template-columns: 1fr;
      }
    }
  </style>
</head>
<body>
  <div id="app">
    <div class="dashboard">
      <header>
        <div class="logo-area">
          <el-icon size="32"><element-plus /></el-icon>
          <div>
            <h1 class="main-title">Element Plus 组件动态插入系统</h1>
            <div class="subtitle">配置属性 · 设置插槽 · 动态渲染 · 尺寸同步</div>
          </div>
        </div>
      </header>
      
      <div class="sidebar">
        <h2><el-icon><operation /></el-icon> 组件库</h2>
        
        <div class="component-list">
          <div class="component-card" @click="selectComponent('ElButton')">
            <h3><el-icon></el-icon> 按钮</h3>
            <div class="desc">可配置多种类型、尺寸和状态的按钮</div>
          </div>
          <div class="component-card" @click="selectComponent('ElInput')">
            <h3><el-icon><edit /></el-icon> 输入框</h3>
            <div class="desc">支持多种类型输入的组件</div>
          </div>
          <div class="component-card" @click="selectComponent('ElCard')">
            <h3><el-icon><data-board /></el-icon> 卡片</h3>
            <div class="desc">带有标题和操作的卡片容器</div>
          </div>
          <div class="component-card" @click="selectComponent('ElTag')">
            <h3><el-icon><price-tag /></el-icon> 标签</h3>
            <div class="desc">用于标记和选择的标签组件</div>
          </div>
          <div class="component-card" @click="selectComponent('ElProgress')">
            <h3><el-icon><loading /></el-icon> 进度条</h3>
            <div class="desc">展示操作进度的组件</div>
          </div>
          <div class="component-card" @click="selectComponent('ElSwitch')">
            <h3><el-icon><switch /></el-icon> 开关</h3>
            <div class="desc">表示两种状态切换的开关</div>
          </div>
        </div>
        
        <div class="config-panel">
          <div class="config-header">
            <el-icon :size="24"><setting /></el-icon>
            <h2>配置参数</h2>
          </div>
          
          <div class="panel-content">
            <template v-if="currentComponent">
              <div class="panel-row" v-if="currentComponent === 'ElButton'">
                <span class="panel-label">按钮文本</span>
                <el-input v-model="config.buttonText" size="small"></el-input>
              </div>
              
              <div class="panel-row" v-if="currentComponent === 'ElButton'">
                <span class="panel-label">按钮类型</span>
                <el-select v-model="config.buttonType" size="small">
                  <el-option label="主要" value="primary"></el-option>
                  <el-option label="成功" value="success"></el-option>
                  <el-option label="警告" value="warning"></el-option>
                  <el-option label="危险" value="danger"></el-option>
                  <el-option label="信息" value="info"></el-option>
                </el-select>
              </div>
              
              <div class="panel-row" v-if="currentComponent === 'ElInput'">
                <span class="panel-label">占位符</span>
                <el-input v-model="config.placeholder" size="small"></el-input>
              </div>
              
              <div class="panel-row" v-if="currentComponent === 'ElCard'">
                <span class="panel-label">卡片标题</span>
                <el-input v-model="config.cardTitle" size="small"></el-input>
              </div>
              
              <div class="panel-row" v-if="currentComponent === 'ElCard'">
                <span class="panel-label">卡片内容</span>
                <el-input 
                  v-model="config.cardContent" 
                  type="textarea" 
                  rows="2" 
                  size="small"
                ></el-input>
              </div>
              
              <div class="panel-row" v-if="currentComponent === 'ElProgress'">
                <span class="panel-label">进度值</span>
                <el-slider v-model="config.progressValue"></el-slider>
              </div>
              
              <div class="panel-row">
                <el-button 
                  type="primary" 
                  size="small" 
                  @click="addComponent"
                  :icon="Plus"
                >
                  添加组件
                </el-button>
              </div>
            </template>
            
            <div v-else class="empty-state">
              <el-icon><search /></el-icon>
              <p>请从左侧选择要添加的组件</p>
            </div>
          </div>
        </div>
      </div>
      
      <div class="editor-area">
        <div class="editor-header">
          <h2><el-icon><monitor /></el-icon> 渲染区域</h2>
          <div class="toolbar">
            <el-button @click="clearAll" :icon="Delete" type="danger" size="small">
              清空组件
            </el-button>
          </div>
        </div>
        
        <div class="viewport-container" ref="viewport">
          <div class="parent-container" id="parentContainer">
            <!-- 动态添加的组件将在这里渲染 -->
            <div v-for="(comp, index) in components" :key="comp.id" class="child-wrapper">
              <div class="size-label">
                {{ comp.width }}×{{ comp.height }}px
              </div>
              <div class="close-btn" @click="removeComponent(index)">
                <el-icon><close-bold /></el-icon>
              </div>
              
              <!-- 动态渲染 Element Plus 组件 -->
              <div :ref="el => { if (el) compRefs[index] = el }">
                <el-card v-if="comp.type === 'ElCard'" shadow="hover" style="width: 240px;">
                  <template #header>
                    <div class="card-header">
                      <span>{{ comp.props.title || '默认标题' }}</span>
                    </div>
                  </template>
                  <div>{{ comp.props.content || '默认卡片内容' }}</div>
                </el-card>
                
                <el-button 
                  v-if="comp.type === 'ElButton'" 
                  :type="comp.props.type" 
                  :icon="comp.props.icon"
                >
                  {{ comp.props.text || '按钮' }}
                </el-button>
                
                <el-input 
                  v-if="comp.type === 'ElInput'"
                  :placeholder="comp.props.placeholder || '请输入内容'"
                  style="width: 220px;"
                ></el-input>
                
                <el-tag 
                  v-if="comp.type === 'ElTag'"
                  type="success"
                  size="large"
                >
                  标签组件
                </el-tag>
                
                <el-progress 
                  v-if="comp.type === 'ElProgress'"
                  :percentage="comp.props.value"
                  style="width: 220px;"
                ></el-progress>
                
                <el-switch 
                  v-if="comp.type === 'ElSwitch'"
                  v-model="comp.props.value"
                  active-text="开启"
                  inactive-text="关闭"
                  style="--el-switch-on-color: #13ce66;"
                ></el-switch>
              </div>
            </div>
          </div>
          
          <div class="info-panel" v-if="components.length">
            <h3 class="info-title"><el-icon><info-filled /></el-icon> 父容器信息</h3>
            <div class="info-grid">
              <div class="info-label">宽度:</div>
              <div class="info-value">{{ parentWidth }}px</div>
              <div class="info-label">高度:</div>
              <div class="info-value">{{ parentHeight }}px</div>
              <div class="info-label">组件数量:</div>
              <div class="info-value">{{ components.length }} 个</div>
            </div>
          </div>
          
          <div v-if="!components.length" class="empty-state">
            <el-result icon="info">
              <template #title>
                暂未添加组件
              </template>
              <template #sub-title>
                请从左侧面板选择组件类型并添加
              </template>
            </el-result>
          </div>
        </div>
      </div>
    </div>
  </div>

  <script>
    const { createApp, ref, reactive, onMounted, onBeforeUnmount, nextTick } = Vue
    const { Plus, Delete, Search, InfoFilled } = ElementPlusIconsVue
    
    const app = createApp({
      setup() {
        // 当前选择的组件类型
        const currentComponent = ref(null)
        
        // 配置数据
        const config = reactive({
          buttonText: '动态按钮',
          buttonType: 'primary',
          placeholder: '请输入内容',
          cardTitle: '卡片标题',
          cardContent: '动态卡片内容',
          progressValue: 50
        })
        
        // 组件列表
        const components = reactive([])
        const compRefs = ref([])
        const viewport = ref(null)
        
        // 父容器尺寸
        const parentWidth = ref(400)
        const parentHeight = ref(300)
        
        // 用于存储观察器实例
        const observers = new Map()
        
        // 选择组件类型
        function selectComponent(type) {
          currentComponent.value = type
        }
        
        // 添加新组件
        function addComponent() {
          if (!currentComponent.value) return
          
          const compData = {
            id: `comp-${Date.now()}`,
            type: currentComponent.value,
            width: 0,
            height: 0,
            props: {},
            slots: {}
          }
          
          // 根据组件类型设置默认属性和插槽
          switch(currentComponent.value) {
            case 'ElButton':
              compData.props = {
                text: config.buttonText,
                type: config.buttonType
              }
              break
            case 'ElInput':
              compData.props = {
                placeholder: config.placeholder
              }
              break
            case 'ElCard':
              compData.props = {
                title: config.cardTitle,
                content: config.cardContent
              }
              break
            case 'ElProgress':
              compData.props = {
                value: config.progressValue
              }
              break
            case 'ElSwitch':
              compData.props = {
                value: true
              }
              break
          }
          
          components.push(compData)
          
          // 设置组件尺寸观察器
          nextTick(() => {
            // 观察最新添加的组件
            const newCompRef = compRefs.value[components.length - 1]
            if (!newCompRef) return
            
            const observer = new ResizeObserver(entries => {
              for (let entry of entries) {
                const rect = entry.contentRect
                const compIndex = components.findIndex(c => 
                  compRefs.value[compIndex] === entry.target
                )
                
                if (compIndex !== -1) {
                  components[compIndex].width = Math.round(rect.width)
                  components[compIndex].height = Math.round(rect.height)
                  updateParentSize()
                }
              }
            })
            
            observer.observe(newCompRef)
            
            // 存储观察器实例
            observers.set(compData.id, {
              observer,
              element: newCompRef
            })
          })
        }
        
        // 更新父容器尺寸
        function updateParentSize() {
          if (components.length === 0) {
            parentWidth.value = 400
            parentHeight.value = 300
            return
          }
          
          // 计算最大宽高
          let maxWidth = 0
          let maxHeight = 0
          
          components.forEach(comp => {
            if (comp.width > maxWidth) maxWidth = comp.width
            if (comp.height > maxHeight) maxHeight = comp.height
          })
          
          // 添加边距
          parentWidth.value = Math.max(400, maxWidth + 100)
          parentHeight.value = Math.max(300, maxHeight * components.length + 80)
        }
        
        // 移除单个组件
        function removeComponent(index) {
          const comp = components[index]
          
          // 停止对应组件的观察器
          const observerInfo = observers.get(comp.id)
          if (observerInfo) {
            observerInfo.observer.disconnect()
            observers.delete(comp.id)
          }
          
          // 移除组件
          components.splice(index, 1)
          updateParentSize()
        }
        
        // 清除所有组件
        function clearAll() {
          // 停止所有观察器
          for (const { observer } of observers.values()) {
            observer.disconnect()
          }
          observers.clear()
          
          // 清空组件数组
          components.splice(0, components.length)
          parentWidth.value = 400
          parentHeight.value = 300
        }
        
        // 组件卸载时清理观察器
        onBeforeUnmount(() => {
          for (const { observer } of observers.values()) {
            observer.disconnect()
          }
          observers.clear()
        })
        
        return {
          Plus,
          Delete,
          Search,
          InfoFilled,
          currentComponent,
          config,
          components,
          compRefs,
          viewport,
          parentWidth,
          parentHeight,
          selectComponent,
          addComponent,
          removeComponent,
          clearAll
        }
      }
    })
    
    // 注册图标
    for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
      app.component(key, component)
    }
    
    // 使用 Element Plus
    app.use(ElementPlus)
    
    // 全局注册图标组件
    app.component('ElIcon', ElementPlus.ElIcon)
    
    app.mount('#app')
  </script>
</body>
</html>